'''
Created on 15.06.2012

@author: dominik
'''
import Image, ImageDraw

class PrototypeRenderer(object):
    '''
    Prototype for a renderer that draws sequence charts.
    '''

    def __init__(self, actors, actions, theme):
        '''
        Constructor
        '''
        if not actors:
            raise ValueError, "Actors list may not be empty."

        self.actors = actors
        self.actions = actions
        self.theme = theme
        self.sizes = {}
        self.positions = {}

    def get_image(self):
        """
        Generate the image for the model.
        """
        self.calc_dimensions()
        
        image = Image.new("RGBA",
                          (self.sizes["image.width"],
                           self.sizes["image.height"]),
                          "white")

        image.paste(self.draw_actor_line(), self.positions["actor_line.top"])
        image.paste(self.draw_actor_line(), self.positions["actor_line.bottom"])
        
        draw = ImageDraw.Draw(image)
        start_y = self.positions["action_lines.start.y"]
        end_y = self.positions["action_lines.end.y"]
        for actor in self.actors:
            x = self.positions["actor."+actor+".center.x"] + self.theme.IMAGE_PADDING
            draw.line((x, start_y, x, end_y), fill="black")
        
        return image

    def draw_actor_line(self):
        """
        Draw an image containing the row of actors.
        """
        image = Image.new("RGBA", 
                           (self.sizes["actor_line.width"],
                            self.sizes["actor_line.height"]),
                           "white")
        for actor in self.actors:
            image.paste(self.draw_single_actor(actor), self.positions["actor."+actor])
        return image

    def draw_single_actor(self, name):
        """ Draw the box with label for a single actor. """
        width = self.sizes["actor."+name+".width"]
        height = self.sizes["actor."+name+".height"]
        image = Image.new("RGBA", (width, height), "white")

        draw = ImageDraw.Draw(image)
        draw.rectangle((0, 0, width - 1, height - 1) , outline="black")
        draw.text((self.theme.ACTOR_PADDING_X, self.theme.ACTOR_PADDING_Y),
                  name, font=self.theme.font_head, fill="black")
        return image

    def calc_dimensions(self):
        """
        Iterates over the complete model and calculates various sizes and
        positions that are used for the drawing process.
        
        Fills self.sizes and self.positions.
        """
        self.positions["actor_line.top"] = (self.theme.IMAGE_PADDING, 
                                            self.theme.IMAGE_PADDING)

        self.calc_actor_sizes()

        width = self.theme.IMAGE_PADDING * 2
        width += self.sizes["actor_line.width"]

        height = self.theme.IMAGE_PADDING * 2
        height += self.sizes["actor_line.height"] * 2 # The actor row is at top and bottom

        self.sizes["image.width"] = width
        self.sizes["image.height"] = height + 30

        bottom_actor_y = self.sizes["image.height"]
        bottom_actor_y -= self.theme.IMAGE_PADDING
        bottom_actor_y -= self.sizes["actor_line.height"]
        self.positions["actor_line.bottom"] = (self.theme.IMAGE_PADDING,
                                               bottom_actor_y)
        
        self.positions["action_lines.start.y"] = self.theme.IMAGE_PADDING + self.sizes["actor_line.height"]
        self.positions["action_lines.end.y"] = bottom_actor_y

    def calc_actor_sizes(self):
        """
        Calculate the sizes and positions for the actors
        and the actor line.
        """
        width = 0
        height = 0

        x = self.positions["actor_line.top"][0]

        for actor in self.actors:
            self.positions["actor."+actor] = (x, 0)
            actor_width = self.theme.ACTOR_PADDING_X * 2
            actor_width += self.theme.font_head.getsize(actor)[0]
            self.sizes["actor."+actor+".width"] = actor_width

            width += actor_width
            
            self.positions["actor."+actor+".center.x"] = x + (actor_width / 2)
            width += self.theme.ACTOR_MARGIN_X
            x = width

            actor_height =self.theme.ACTOR_PADDING_Y * 2
            actor_height += self.theme.font_head.getsize(actor)[1]
            self.sizes["actor."+actor+".height"] = actor_height
            height = max(height, actor_height)

        width -= self.theme.ACTOR_MARGIN_X # Remove margin after last actor
        self.sizes["actor_line.width"] = width
        self.sizes["actor_line.height"] = height

